<template>
  <el-card class="mt-10">
    <el-form
      label-width="100px"
      ref="spuFormRef"
      :model="spuFormData"
      :rules="spuFormRules"
    >
      <el-form-item label="SPU名称" prop="spuName">
        <el-input placeholder="请输入SPU名称" v-model="spuFormData.spuName" />
      </el-form-item>
      <el-form-item label="品牌" prop="tmId">
        <el-select placeholder="请选择品牌" v-model="spuFormData.tmId">
          <el-option
            v-for="tm in trademarkList"
            :key="tm.id"
            :label="tm.tmName"
            :value="tm.id"
          />
        </el-select>
      </el-form-item>
      <el-form-item label="SPU描述" prop="description">
        <el-input
          :rows="2"
          type="textarea"
          placeholder="请输入SPU描述"
          v-model="spuFormData.description"
        />
      </el-form-item>
      <el-form-item label="SPU图片" prop="spuImageList">
        <!-- 
          上传图片组件 
            v-model:file-list="xxx" 上传图片成功，自动添加数据进入
            action 上传服务器地址
            list-type="picture-card" 卡片风格
            :on-preview 点击预览触发的回调
            :on-remove 点击删除触发的回调
            :limit="3" 允许上传文件的最大数量
        -->
        <el-upload
          class="spu-upload"
          v-model:file-list="spuFormData.spuImageList"
          :action="`${BASE_URL}/admin/product/fileUpload`"
          list-type="picture-card"
          :on-preview="handlePictureCardPreview"
          :before-upload="beforeAvatarUpload"
          :on-success="handleAvatarSuccess"
          :limit="MAX_UPLOAD_NUM"
        >
          <el-icon><Plus /></el-icon>
          <template #tip>
            <div class="el-upload__tip">只能上传jpg/png文件，且不超过250kb</div>
          </template>
        </el-upload>
        <!-- 预览图片 -->
        <el-dialog v-model="dialogVisible" width="30%">
          <img class="spu-img" :src="dialogImageUrl" alt="Preview Image" />
        </el-dialog>
      </el-form-item>
      <el-form-item label="销售属性" prop="spuSaleAttrList">
        <el-select
          :placeholder="
            filterBaseSaleAttrList.length
              ? `还剩 ${filterBaseSaleAttrList.length} 个未选择`
              : '没有啦！'
          "
          v-model="selectedBaseSaleAttr"
        >
          <el-option
            v-for="baseSaleAttr in filterBaseSaleAttrList"
            :key="baseSaleAttr.id"
            :label="baseSaleAttr.name"
            :value="`${baseSaleAttr.id}:${baseSaleAttr.name}`"
          />
        </el-select>
        <el-button
          type="primary"
          :icon="Plus"
          class="ml-10"
          :disabled="!selectedBaseSaleAttr"
          @click="addSaleAttr"
        >
          添加销售属性
        </el-button>
        <el-table :data="spuFormData.spuSaleAttrList" border class="mt-20">
          <el-table-column
            label="序号"
            type="index"
            align="center"
            width="60"
          />
          <el-table-column label="属性名" prop="saleAttrName" width="200" />
          <el-table-column label="属性值名称列表">
            <template v-slot="{ row }">
              <el-tag
                v-for="(saleAttrValue, index) in row.spuSaleAttrValueList"
                :key="saleAttrValue.saleAttrValueName"
                class="mr-10"
                closable
                @close="delSaleAttrValue(row.spuSaleAttrValueList, index)"
              >
                {{ saleAttrValue.saleAttrValueName }}
              </el-tag>
              <el-input
                size="small"
                v-if="row.isEdit"
                class="spu-input"
                ref="inputRef"
                v-model="saleAttrValueName"
                @blur="switchShow(row)"
              />
              <el-button
                :icon="Plus"
                size="small"
                v-else
                @click="switchEdit(row)"
              />
            </template>
          </el-table-column>
          <el-table-column label="操作" width="100">
            <template v-slot="{ $index }">
              <el-button
                type="danger"
                :icon="Delete"
                size="small"
                @click="delSaleAttr($index)"
              />
            </template>
          </el-table-column>
        </el-table>
      </el-form-item>

      <el-form-item>
        <el-button type="primary" @click="addOrUpdateSpu">确定</el-button>
        <el-button @click="showSpuList">取消</el-button>
      </el-form-item>
    </el-form>
  </el-card>
</template>

<script lang="ts">
export default {
  name: "AddOrUpdateSpu",
};
</script>

<script lang="ts" setup>
import { ref, onMounted, reactive, computed, nextTick } from "vue";
import { Plus, Delete } from "@element-plus/icons-vue";
import { getAllTrademarkListApi } from "@/api/product/trademark";
import {
  getBaseSaleAttrListApi,
  saveSpuApi,
  updateSpuApi,
  getSpuImageListApi,
  getSpuSaleAttrListApi,
} from "@/api/product/spu";
import type { TrademarkList } from "@/api/product/model/trademarkModel";
import type {
  BaseSaleAttrList,
  SpuFormData,
  SpuSaleAttrValueList,
  SpuSaleAttrList,
  SpuSaleAttrItem,
} from "@/api/product/model/spuModel";
import { ElMessage } from "element-plus";
import type { FormInstance, FormRules, UploadProps } from "element-plus";
import { useCategoryStore } from "@/stores/category";
import { useSpuStore } from "@/stores/spu";

const selectedBaseSaleAttr = ref("");
// 销售属性功能
const filterBaseSaleAttrList = computed(() => {
  /*
    对baseSaleAttrList进行遍历，判断遍历出来的销售属性在不在spuFormData.spuSaleAttrList中
      在，过滤 false
      不在，保留 true

    baseSaleAttrList基础销售属性列表
      [{ id: xx, name: xx }]
    spuFormData.spuSaleAttrList销售属性列表
      [{ baseSaleAttrId: xx, saleAttrName: xx, spuSaleAttrValueList: [] }]
        baseSaleAttrId其实就来自于基础销售属性的id
        saleAttrName其实就来自于基础销售属性的name
  */
  return baseSaleAttrList.value.filter((baseSaleAttr) => {
    return !spuFormData.spuSaleAttrList.some(
      (spuSaleAttr) => spuSaleAttr.baseSaleAttrId === baseSaleAttr.id
    );
  });
});
// 添加销售属性
const addSaleAttr = () => {
  const [id, name] = selectedBaseSaleAttr.value.split(":");

  spuFormData.spuSaleAttrList.push({
    baseSaleAttrId: +id,
    saleAttrName: name,
    spuSaleAttrValueList: [],
    isEdit: false, // 默认显示显示模式
  });
  // 清空选中的值
  selectedBaseSaleAttr.value = "";
};

// 删除销售属性
const delSaleAttr = (index: number) => {
  spuFormData.spuSaleAttrList.splice(index, 1);
};

const inputRef = ref();

// 切换编辑模式
const switchEdit = async (row: SpuSaleAttrItem) => {
  row.isEdit = true;
  await nextTick();
  inputRef.value.focus();
};

const saleAttrValueName = ref("");

// 切换显示模式
const switchShow = (row: SpuSaleAttrItem) => {
  if (saleAttrValueName.value) {
    row.spuSaleAttrValueList.push({
      baseSaleAttrId: row.baseSaleAttrId,
      saleAttrValueName: saleAttrValueName.value,
    });

    saleAttrValueName.value = "";
  }

  row.isEdit = false;
};

// 删除销售属性值
const delSaleAttrValue = (
  spuSaleAttrValueList: SpuSaleAttrValueList,
  index: number
) => {
  spuSaleAttrValueList.splice(index, 1);
};

// ref数据，用来获取form组件实例对象
const spuFormRef = ref<FormInstance>();

const spuStore = useSpuStore();
// 整个表单数据
const spuFormData = reactive<SpuFormData>({
  // 数据名称看接口文档
  spuName: spuStore.spuName,
  tmId: spuStore.tmId,
  description: spuStore.description,
  spuImageList: [],
  spuSaleAttrList: [],
});

const spuSaleAttrListValidator = (
  rule: any,
  value: SpuSaleAttrList,
  callback: any
) => {
  /*
    rule 当前校验规则的信息
    value 当前校验表单的数据 spuSaleAttrList的值
    callback 是一个函数
      callback() 不传参数，就是校验通过
      callback(new Error('xxx')) 传参数，就是校验失败
        传递的参数就是失败的原因，就是错误提示信息

    需求：
      1. 至少添加一个销售属性
      2. 每个销售属性至少添加一个销售属性值
  */

  // 1. 至少添加一个销售属性
  if (!value.length) {
    callback(new Error("请至少添加一个销售属性"));
    return;
  }

  // 2. 每个销售属性至少添加一个销售属性值
  if (!value.every((saleAttr) => saleAttr.spuSaleAttrValueList.length)) {
    callback(new Error("每个销售属性至少添加一个销售属性值"));
    return;
  }

  // 必须要调用
  callback();
};

// 表单的校验规则
const spuFormRules = reactive<FormRules>({
  // 规则名称必须和数据名称一致
  spuName: [{ required: true, message: "请输入SPU名称", trigger: "blur" }],
  tmId: [{ required: true, message: "请选择品牌", trigger: "change" }],
  description: [{ required: true, message: "请输入SPU描述", trigger: "blur" }],
  spuImageList: [{ required: true, message: "请上传SPU图片" }],
  // 自定义校验规则，校验时调用函数，函数内部告诉校验通过还是失败，以及失败的原因
  spuSaleAttrList: [
    { required: true, validator: spuSaleAttrListValidator, trigger: "blur" },
  ],
});

// 上传图片功能
const BASE_URL = import.meta.env.VITE_API_URL;

const dialogImageUrl = ref("");
const dialogVisible = ref(false);
// 预览
const handlePictureCardPreview: UploadProps["onPreview"] = (uploadFile) => {
  dialogImageUrl.value = uploadFile.url as string;
  dialogVisible.value = true;
};
// 文件上传之前触发的函数
const beforeAvatarUpload: UploadProps["beforeUpload"] = (rawFile) => {
  // rawFile 上传的文件对象
  // rawFile.type 文件类型
  // rawFile.size 文件大小
  const validImageType = ["image/jpeg", "image/jpg", "image/png"];

  if (!validImageType.includes(rawFile.type)) {
    ElMessage.error("图片类型只能是jpeg、jpg或png格式!");
    // 不会继续上传
    return false;
  } else if (rawFile.size / 1024 > 250) {
    ElMessage.error("图片大小必须小于250kb!");
    return false;
  }
  // 继续上传图片
  return true;
};

const MAX_UPLOAD_NUM = 10;
// 是否显示上传按钮
const isShowUploadBtn = computed(() => {
  return spuFormData.spuImageList.length < MAX_UPLOAD_NUM
    ? "inline-flex"
    : "none";
});

// 上传图片成功
const handleAvatarSuccess = () => {
  if (spuFormData.spuImageList.length === 1) {
    spuFormRef.value?.clearValidate(["spuImageList"]);
  }
};

const trademarkList = ref<TrademarkList>([]);
const baseSaleAttrList = ref<BaseSaleAttrList>([]);

// vue2中处理多个请求的方式
// {
//   async mounted() {
//     await Promise.all([getAllTrademarkListApi(), getBaseSaleAttrListApi()])
//   },
//   mounted() {
//     this.getAllTrademarkList()
//     this.getBaseSaleAttrList()
//   },
//   async getAllTrademarkList() {
//     trademarkList.value = await getAllTrademarkListApi();
//   },
//   async getBaseSaleAttrList() {
//     baseSaleAttrList.value = await getBaseSaleAttrListApi();
//   }
// }

onMounted(async () => {
  trademarkList.value = await getAllTrademarkListApi();
});

onMounted(async () => {
  baseSaleAttrList.value = await getBaseSaleAttrListApi();
});

onMounted(async () => {
  const id = spuStore.id;
  if (id) {
    // 发送请求或请求图片数据得到数据：[{imgName: xxx, imgUrl: xxx}]
    // 上传图片组件需要的数据：[{name: xxx, url: xxx}]
    const spuImageList = await getSpuImageListApi(id);
    spuFormData.spuImageList = spuImageList.map((img) => {
      return {
        name: img.imgName,
        url: img.imgUrl,
      };
    });
  }
});

onMounted(async () => {
  const id = spuStore.id;
  if (id) {
    spuFormData.spuSaleAttrList = await getSpuSaleAttrListApi(id);
  }
});

const emit = defineEmits(["setIsShow"]);

// 显示添加SPU
const showSpuList = () => {
  emit("setIsShow", 1);
};

const categoryStore = useCategoryStore();

// 添加或更新SPU
const addOrUpdateSpu = async () => {
  await spuFormRef.value?.validate();
  const id = spuStore.id;

  const data = {
    ...spuFormData,
    tmId: spuFormData.tmId as number,
    spuImageList: spuFormData.spuImageList.map((img) => {
      return {
        imgName: img.name,
        // imgUrl: img.url, // 本地浏览图片地址
        // TypeError: Cannot read properties of undefined (reading 'data')
        // 新上传图片地址img.response.data, 请求回来的图片地址img.url
        // imgUrl: (img.response as { data: string }).data, // 在线访问地址
        imgUrl: img.response
          ? (img.response as { data: string }).data
          : (img.url as string), // 在线访问地址
        // imgUrl: (img.response as any).data, // 在线访问地址
      };
    }),
    category3Id: categoryStore.category3Id as number,
  };

  if (id) {
    updateSpuApi({
      ...data,
      id,
    });
  } else {
    await saveSpuApi(data);
  }

  ElMessage.success(`${id ? "修改" : "添加"}SPU成功`);

  showSpuList();
};
</script>

<style scoped>
.spu-img {
  width: 100%;
}

.spu-upload :deep(.el-upload) {
  display: v-bind(isShowUploadBtn);
}

.spu-input {
  width: 150px;
}
</style>
